﻿using SHZY.Common.Core.Manager;
using SHZY.Common.Enum;
using SHZY.Common.Extension;
using SHZY.Common.Filter;
using SHZY.Common.Security;
using SHZY.DependencyInjection;
using SHZY.DynamicApiController;
using SHZY.FriendlyException;
using SHZY.Systems.Entitys.System;
using SHZY.Systems.Interfaces.System;
using SHZY.Business.Entitys.Dto.QmsBusiInspectionlot;
using SHZY.Business.Entitys;
using SHZY.Business.Interfaces;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using Newtonsoft.Json.Linq;
using SHZY.Business.Entitys.Entity;
using SHZY.BaseData.Entitys;
using SHZY.Common.FR;
using StackExchange.Profiling.Internal;
using SHZY.BaseData.Interfaces;
using SHZY.WorkFlow.Entitys.Model.Item;
using Mapster;
using SHZY.BaseData.Entitys.Dto.QmsBaseMaterial;
using SHZY.Systems.Entitys.Permission;

namespace SHZY.Business;

/// <summary>
/// 业务实现：检验批.
/// </summary>
[ApiDescriptionSettings(Tag = "Business", Name = "Inspectionlot", Order = 200)]
[Route("api/Business/[controller]")]
public class QmsBusiInspectionlotService : IQmsBusiInspectionlotService, IDynamicApiController, ITransient
{
    /// <summary>
    /// 服务基础仓储.
    /// </summary>
    private readonly ISqlSugarRepository<QmsBusiInspectionlotEntity> _repository;

    /// <summary>
    /// 数据接口服务.
    /// </summary>
    private readonly IDataInterfaceService _dataInterfaceService;

    /// <summary>
    /// 用户管理.
    /// </summary>
    private readonly IUserManager _userManager;

    private readonly ITenant _db;
    /// <summary>
    /// 单据编号服务
    /// </summary>
    private readonly IBillRullService _billRullService;

    /// <summary>
    /// 检验批项目服务
    /// </summary>
    private readonly IQmsBusiInspectionitemService _iqmsBusiInspectionitemService;

    /// <summary>
    /// 跳检规则分配
    /// </summary>
    private readonly IQmsBaseExemptionruleService _iqmsBaseExemptionruleService;

    /// <summary>
    /// 数据字典服务.
    /// </summary>
    private readonly IDictionaryDataService _dictionaryDataService;

    /// <summary>
    /// 消息模板.
    /// </summary>
    private readonly IMessageTemplateService _messageTemplateService;

    /// <summary>
    /// 初始化一个<see cref="QmsBusiInspectionlotService"/>类型的新实例.
    /// </summary>
    public QmsBusiInspectionlotService(
        ISqlSugarRepository<QmsBusiInspectionlotEntity> qmsBusiInspectionlotRepository,
        IDataInterfaceService dataInterfaceService,
        ISqlSugarClient context,
        IUserManager userManager,
         IDictionaryDataService dictionaryDataService,
        IQmsBusiInspectionitemService iqmsBusiInspectionitemService,
        IBillRullService billRullService,
        IQmsBaseExemptionruleService qmsBaseExemptionruleService,
        IMessageTemplateService messageTemplateService
        )
    {
        _repository = qmsBusiInspectionlotRepository;
        _dataInterfaceService = dataInterfaceService;
        _userManager = userManager;
        _iqmsBusiInspectionitemService = iqmsBusiInspectionitemService;
        _dictionaryDataService = dictionaryDataService;
        _db = context.AsTenant();
        _billRullService = billRullService;
        _iqmsBaseExemptionruleService = qmsBaseExemptionruleService;
        _messageTemplateService = messageTemplateService;

    }

    /// <summary>
    /// 获取检验批.
    /// </summary>
    /// <param name="id">主键值.</param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<dynamic> GetInfo(string id)
    {
        var data = await _repository.FirstOrDefaultAsync(x => x.Id == id);
        var entity = data.Adapt<QmsBusiInspectionlotInfoOutput>();
        entity.materialDes = "";
        var materialInfo = await _repository.Context.Queryable<QmsBaseMaterialEntity>().Where(x => x.Code == entity.materialCode && x.DeleteMark == null).FirstAsync();
        if(materialInfo != null)
        {
            entity.materialDes = materialInfo.Name;
        }

        entity.supplierDes = "";
        var supplierInfo = await _repository.Context.Queryable<QmsBaseSupplierEntity>().Where(x => x.Code == entity.supplier && x.DeleteMark == null).FirstAsync();
        if (supplierInfo != null)
        {
            entity.supplierDes = supplierInfo.Name;
        }

        entity.employeeId = "";
        var userInfo = await _repository.Context.Queryable<UserEntity>().Where(x => x.Account == entity.employeeCode && x.DeleteMark == null).FirstAsync();
        if (userInfo != null)
        {
            entity.employeeId = userInfo.Id;
        }

        return entity;
    }

    /// <summary>
    /// 获取检验批列表.
    /// </summary>
    /// <param name="input">请求参数.</param>
    /// <returns></returns>
    [HttpGet("")]
    public async Task<dynamic> GetList([FromQuery] QmsBusiInspectionlotListQueryInput input)
    {
        var queryable = _repository.Context.Queryable<QmsBusiInspectionlotEntity, QmsBaseMaterialEntity, QmsBaseSupplierEntity>((a, b, c) => new JoinQueryInfos(JoinType.Left, a.MaterialCode == b.Code, JoinType.Left, a.Supplier == c.Code))
            .WhereIF(!string.IsNullOrEmpty(input.code), a => a.Code.Contains(input.code))
            .Where(a => a.DeleteMark == null)
            .WhereIF(input.status != null, a => a.Status == input.status)
            .WhereIF(!string.IsNullOrEmpty(input.statusType) && input.statusType == "Wait", a => a.Status == 0 || a.Status == 1)
            .WhereIF(!string.IsNullOrEmpty(input.statusType) && input.statusType == "Finish", a => a.Status == 2)
            .WhereIF(!string.IsNullOrEmpty(input.judgeStatus), a => a.JudgeStatus == input.judgeStatus)
            .WhereIF(!string.IsNullOrEmpty(input.type), a => a.Type.Contains(input.type))
            .WhereIF(!string.IsNullOrEmpty(input.material), (a, b, c) => b.Code.Contains(input.material) || b.Type.Contains(input.material))
            .WhereIF(!string.IsNullOrEmpty(input.supplier), (a, b, c) => c.Code.Contains(input.supplier) || c.Type.Contains(input.supplier))
            .WhereIF(!string.IsNullOrEmpty(input.batchNumber), a => a.BatchNumber.Contains(input.batchNumber))
            .Select((a, b, c) => new QmsBusiInspectionlotListOutput
            {
                id = a.Id,
                code = a.Code,
                date = a.Date,
                type = a.Type,
                materialCode = a.MaterialCode,
                materialDes = b.Name,
                supplier = a.Supplier,
                supplierDes = c.Name,
                incomingQty = a.IncomingQty,
                batchNumber = a.BatchNumber,
                employeeCode = a.EmployeeCode,
                employeeName = a.EmployeeName,
                orderNo = a.OrderNo,
                inspectType = a.InspectType,
                remark = a.Remark,
                status = a.Status,
                judgeStatus = a.JudgeStatus,
                udNo = a.UdNo,
                decision = a.Decision,
                decisionName = a.DecisionName,
                destructivenessQty = a.DestructivenessQty,
                receiveQty = a.ReceiveQty,
                decisionDesc = a.DecisionDesc,
                overdue = a.Overdue,
                enabledMark = a.EnabledMark,
                parameter = a.Parameter,
                ruleCode = a.RuleCode,
                ruleDesc = a.RuleDesc,
                ruleStage = a.RuleStage,
                ruleStageDesc = a.RuleStageDesc,
                startTime = a.StartTime,
                endTime = a.EndTime,
                exempt = a.Exempt,
                creatorTime = a.CreatorTime
            }).MergeTable();
            //.OrderByIF(string.IsNullOrEmpty(input.sidx), " a.F_StartTime desc,a.F_CreatorTime asc");
        if (!string.IsNullOrEmpty(input.sidx))
        {
            queryable.OrderBy(input.sidx + " " + input.sort);
        }
        else
        {
            queryable.OrderByDescending(it =>it.startTime).OrderBy(it =>it.creatorTime);
        }

        var data = await queryable.ToPagedListAsync(input.currentPage, input.pageSize);
        // 检验完成待过账并是NG状态，则需要查询返回报检单相关数据用于过账操作
        if (!string.IsNullOrEmpty(input.statusType) && input.statusType == "Finish")
        {
            foreach (var item in data.list)
            {
                JArray jArray = new JArray();
                var inspectionList = await _repository.Context.Queryable<QmsBusiInspectionEntity>().Where(x => x.InspectionlogCode == item.code && x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Asc).ToListAsync();
                foreach (var inspection in inspectionList)
                {
                    JObject jObject = new JObject();
                    jObject.Add("code", inspection.Code);
                    jObject.Add("incomingQty", inspection.IncomingQty);
                    jObject.Add("destructivenessQty", "0");
                    jObject.Add("receiveQty", "0");
                    jObject.Add("rejectQty", "0");
                    jObject.Add("decisionDesc", "");
                    jArray.Add(jObject);
                }
                item.inspection = jArray;
            }
        }

        return PageResult<QmsBusiInspectionlotListOutput>.SqlSugarPageResult(data);
    }

    /// <summary>
    /// 保存检验数据.
    /// </summary>
    /// <param name="data">参数.</param>
    /// <returns></returns>
    [HttpPut("")]
    public async Task Save([FromBody] JObject _data)
    {
        string id = _data["id"].ToString();
        string code = _data["code"].ToString();
        string remark = _data["remark"].ToString();
        string parameter = _data["parameter"].ToString();
        // app端检验项目是单独保存接口，pc端保存提交时才执行以下方法
        if (_userManager.UserOrigin.Equals("pc"))
        {

            // 校验是否有检验条目抽样数量是0，如果是0，则需要输入抽样数量
            if (await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == code && x.SamplingQty == 0 && x.DeleteMark == null && x.EnabledMark == 1).CountAsync() > 0)
            {
                throw Oops.Oh("存在检验条目未确认抽样数量，请确认");
            }

            // 保存检验项目数据
            if (!(await _iqmsBusiInspectionitemService.Save(code, _data)))
            {
                throw Oops.Oh("保存检验项目数据异常");
            }
        }

        // 保存检验批信息
        QmsBusiInspectionlotEntity qmsBusiInspectionlotEntity = new QmsBusiInspectionlotEntity();
        qmsBusiInspectionlotEntity.Id = id;
        qmsBusiInspectionlotEntity.Status = 1;
        qmsBusiInspectionlotEntity.Remark = remark;
        qmsBusiInspectionlotEntity.Parameter = parameter;
        // 保存时，如果当前是未检验状态，则记录开始检验时间
        if (await _repository.Context.Queryable<QmsBusiInspectionlotEntity>().Where(x => x.Id == id && x.Status == 0).CountAsync() > 0)
        {
            qmsBusiInspectionlotEntity.Date = DateTime.Now;
            qmsBusiInspectionlotEntity.StartTime = DateTime.Now;
        }

        var isOk = await _repository.Context.Updateable(qmsBusiInspectionlotEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
        if (!isOk)
            throw Oops.Oh(ErrorCode.COM1001);
    }

    /// <summary>
    /// 提交检验数据.
    /// </summary>
    /// <param name="data">参数.</param>
    /// <returns></returns>
    [HttpPost("")]
    public async Task<dynamic> Submit([FromBody] JObject _data)
    {
        string id = _data["id"].ToString();
        string code = _data["code"].ToString();
        string remark = _data["remark"].ToString();
        string parameter = _data["parameter"].ToString();
        string materialCode = _data["materialCode"].ToString();
        string supplier = _data["supplier"].ToString();
        string inspectType = _data["inspectType"].ToString();
        int status = 2;
        string confirmed = _data["confirmed"].ToString();// 二次确认标识

        // 校验是否有检验条目抽样数量是0，如果是0，则需要输入抽样数量
        if (await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == code && x.SamplingQty == 0 && x.DeleteMark == null && x.EnabledMark == 1).CountAsync() > 0)
        {
            throw Oops.Oh("存在检验条目未确认抽样数量，请确认");
        }

        // app端检验项目是单独保存接口，pc端保存提交时才执行以下方法
        if (_userManager.UserOrigin.Equals("pc"))
        {
            // 保存检验项目数据
            if (!(await _iqmsBusiInspectionitemService.Save(code, _data)))
            {
                throw Oops.Oh("保存检验项目数据异常");
            }
        }
        // 提交检验批时校验是否开启了SN号管理
        var materialInfo = await _repository.Context.Queryable<QmsBaseMaterialEntity>().Where(x => x.Code == materialCode && x.DeleteMark == null && x.EnabledMark == 1).FirstAsync();
        if (materialInfo.IsSn.Equals("Y"))
        {
            // 如果序号与标题一致，或者标题为空，则提示检验项目需要填写具体的SN号
            int count = await _repository.Context.Queryable<QmsBusiInspectionitemdataEntity>().Where(x => x.Code == code && x.DeleteMark == null && x.EnabledMark == 1 && string.IsNullOrEmpty(x.Serial)).CountAsync();
            if (count > 0)
            {
                throw Oops.Oh("物料开启了SN号管理，检验项目需要填写具体的SN号");
            }
        }

        // 校验需要输入破坏性数量的检验条目是否没有输入
        if (await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == code && x.Destructiveness == "Y" && x.DestructivenessQty== 0 && x.DeleteMark == null && x.EnabledMark == 1).CountAsync() > 0)
        {
            throw Oops.Oh("存在检验条目未输入破坏性数量，请确认");
        }


        // 校验检验项目是否完成检验结果的输入
        if (await _repository.Context.Queryable<QmsBusiInspectionitemdataEntity>().Where(x => x.Code == code && string.IsNullOrEmpty(x.Status) && x.DeleteMark == null && x.EnabledMark == 1).CountAsync() > 0)
        {
            throw Oops.Oh("存在检验项目未输入检验结果，请确认");
        }

        // 如果有检验项目是NG，则标识检验批NG，排除有参考标识的检验项目
        string judgeStatus = "OK";
        if (await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == code && x.Status == "NG" && x.ReferTo != "Y" && x.DeleteMark == null && x.EnabledMark == 1).CountAsync() > 0)
        {
            judgeStatus = "NG";
        }

        string decision = "";
        string decisionName = "";
        // 提交检验批时，统计破坏性数量
        // 1.合格并且没有破坏性数量，则默认使用合格，接收决策，并标识状态已过账
        // 2.合格并且有破坏性数量，则需要用户二次确认，二次确认后标识状态已过账
        // 3.不合格直接生成不合格品评审单
        // 统计破坏性数量
        int destructivenessQty = (await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().GroupBy(x => new { x.Code }).Where(x => x.Code == code && x.Destructiveness == "Y" && x.DeleteMark == null && x.EnabledMark == 1).Select(x => new
        {
            total = SqlFunc.AggregateSum(x.DestructivenessQty)
        }).FirstAsync())?.total ?? 0;
        // 合格
        if (judgeStatus.Equals("OK"))
        {
            // 1.合格没有破坏性数量，则默认使用合格，接收决策，并标识状态已过账
            // 2.合格并且有破坏性数量，则需要用户二次确认，二次确认后标识状态已过账
            if (destructivenessQty == 0 || confirmed.Equals("Y"))
            {
                decision = "101";
                decisionName = "合格，接收";
                status = 3;
            }
            else
            {
                return new { confirm = "Y" };
            }
        }

        // 填充检验批信息
        QmsBusiInspectionlotEntity qmsBusiInspectionlotEntity = new QmsBusiInspectionlotEntity();
        qmsBusiInspectionlotEntity.Id = id;
        qmsBusiInspectionlotEntity.Decision = decision;
        qmsBusiInspectionlotEntity.DecisionName = decisionName;
        qmsBusiInspectionlotEntity.JudgeStatus = judgeStatus;
        qmsBusiInspectionlotEntity.Status = status;
        qmsBusiInspectionlotEntity.Remark = remark;
        qmsBusiInspectionlotEntity.Parameter = parameter;
        qmsBusiInspectionlotEntity.EndTime = DateTime.Now;
        qmsBusiInspectionlotEntity.DestructivenessQty = destructivenessQty;

        // 保存时，如果当前是未检验状态，则记录开始检验时间
        if (await _repository.Context.Queryable<QmsBusiInspectionlotEntity>().Where(x => x.Id == id && x.Status == 0).CountAsync() > 0)
        {
            qmsBusiInspectionlotEntity.Date = DateTime.Now;
            qmsBusiInspectionlotEntity.StartTime = DateTime.Now;
        }
        try
        {
            // 开启事务
            _repository.Context.BeginTran();
            // 保存检验批信息
            var isOk = await _repository.Context.Updateable(qmsBusiInspectionlotEntity).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
            if (!isOk)
                throw Oops.Oh(ErrorCode.COM1001);

            // 检验批为NG时，生成不合格品处理单
            if (judgeStatus.Equals("NG"))
            {
                await DefectHandle(code);
            }
            // 记录跳检规则
            await RecordRule(qmsBusiInspectionlotEntity.Id, materialCode,  inspectType, supplier, judgeStatus);

            // 提交事务
            _repository.Context.CommitTran();
            return new { confirm = "" };
        }
        catch (Exception ex)
        {
            // 回滚事务
            _repository.Context.RollbackTran();
            throw Oops.Oh(ex.Message);
        }
    }

    /// <summary>
    /// 不合格品处理单.
    /// </summary>
    /// <param name="code">检验批号.</param>
    /// <returns></returns>
    [NonAction]
    public async Task DefectHandle(string code)
    {
        List<QmsBusiDefecthandleEntity> defecthandleList = new List<QmsBusiDefecthandleEntity>();
        List<QmsBusiDefecthandledetailEntity> defecthandledetailList = new List<QmsBusiDefecthandledetailEntity>();
        var inspectionItemList = await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == code && x.Status == "NG" && x.ReferTo != "Y" && x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Asc).ToListAsync();

        // 获取处理单号
        string defectHandleCode = await _billRullService.GetBillNumber("DefectHandle");

        foreach (var inspectionItem in inspectionItemList)
        {
            // 不良数量
            int defectQty = await _repository.Context.Queryable<QmsBusiInspectionitemdataEntity>().Where(x => x.InspectionItem == inspectionItem.Id && x.Status == "NG" && x.DeleteMark == null && x.EnabledMark == 1).CountAsync();

            QmsBusiDefecthandledetailEntity defecthandledetailEntity = new QmsBusiDefecthandledetailEntity();
            defecthandledetailEntity.DefectHandleCode = defectHandleCode;
            defecthandledetailEntity.InspectionItemId = inspectionItem.Id;
            defecthandledetailEntity.InnspectionCode = inspectionItem.InnspectionCode;
            defecthandledetailEntity.InnspectionName = inspectionItem.InnspectionName;
            defecthandledetailEntity.InnspectionEntry = inspectionItem.InnspectionEntry;
            defecthandledetailEntity.InnspectionEntryName = inspectionItem.InnspectionEntryName;
            int samplingQty = inspectionItem.SamplingQty ?? 0;
            defecthandledetailEntity.SamplingQty = samplingQty;
            decimal defectRate = ((decimal)defectQty / (decimal)samplingQty) * 100;
            defectRate = decimal.Round(defectRate, 2);
            defecthandledetailEntity.DefectQty = defectQty;
            defecthandledetailEntity.DefectRate = defectRate;
            defecthandledetailList.Add(defecthandledetailEntity);
        }

        // 如果存在缺陷记录，则需要创建不合格品处理单
        if (defecthandledetailList.Count > 0)
        {
            // 查询检验批信息
            var inspectionlotEntity = await _repository.Context.Queryable<QmsBusiInspectionlotEntity>().Where(x => x.Code == code && x.DeleteMark == null && x.EnabledMark == 1).FirstAsync();

            // 查询物料信息
            var materialEntity = await _repository.Context.Queryable<QmsBaseMaterialEntity>().Where(x => x.Code == inspectionlotEntity.MaterialCode && x.DeleteMark == null && x.EnabledMark == 1).FirstAsync();

            // 查询供应商信息
            var supplierEntity = await _repository.Context.Queryable<QmsBaseSupplierEntity>().Where(x => x.Code == inspectionlotEntity.Supplier && x.DeleteMark == null && x.EnabledMark == 1).FirstAsync();

            QmsBusiDefecthandleEntity defecthandleEntity = new QmsBusiDefecthandleEntity();
            defecthandleEntity.Type = inspectionlotEntity.Type;
            defecthandleEntity.Code = defectHandleCode;
            defecthandleEntity.Status = 0;
            defecthandleEntity.InspectionLotId = inspectionlotEntity.Id;
            defecthandleEntity.InspectionLot = inspectionlotEntity.Code;
            defecthandleEntity.BatchNumber = inspectionlotEntity.BatchNumber;
            defecthandleEntity.MaterialCode = inspectionlotEntity.MaterialCode;
            defecthandleEntity.MaterialDes = materialEntity?.Name;
            defecthandleEntity.Supplier = inspectionlotEntity.Supplier;
            defecthandleEntity.SupplierDes = supplierEntity?.Name;
            defecthandleEntity.IncomingQty = inspectionlotEntity.IncomingQty;
            defecthandleEntity.OrderNo = "";
            defecthandleEntity.ProductionQty = 0;
            defecthandleEntity.Problem = "";
            defecthandleEntity.Decision = "";
            defecthandleEntity.DecisionName = "";
            defecthandleEntity.Remark = "";
            defecthandleList.Add(defecthandleEntity);
        }

        // 新增不合格品处理单
        if (defecthandleList.Count > 0)
        {
            var isOk1 = await _repository.Context.Insertable(defecthandleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
            if (isOk1 < 1)
                throw Oops.Oh(ErrorCode.COM1000);

            var isOk2 = await _repository.Context.Insertable(defecthandledetailList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
            if (isOk2 < 1)
                throw Oops.Oh(ErrorCode.COM1000);
        }
    }

    /// <summary>
    /// 记录跳检规则
    /// </summary>
    /// <param name="id">检验批id</param>
    /// <param name="materialCode">物料编码</param>
    /// <param name="orderType">采购订单类型</param>
    /// <param name="supplierCode">供应商编码</param>
    /// <param name="status">检验批状态：OK或者NG</param>
    /// <returns></returns>
    [NonAction]
    public async Task<bool> RecordRule(string id, string materialCode, string orderType, string supplierCode, string status)
    {
        var data = new QmsBaseInspectionroleEntity();
        var recordInfo = await _repository.Context.Queryable<QmsBusiExemptionrulerecordEntity>().Where(x => x.MatnrCode == materialCode && x.OrderType == orderType && x.SupplierNo == supplierCode && x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Desc).FirstAsync();
        if (recordInfo != null)
        {
            string stage = recordInfo.Stage;
            data = await _repository.Context.Queryable<QmsBaseInspectionrolemainEntity, QmsBaseInspectionroleEntity>((a, b) => a.Id == b.MainId).Where((a, b) => a.Code == recordInfo.RuleCode && b.Stage == stage && a.DeleteMark == null && a.EnabledMark == 1 && b.DeleteMark == null && b.EnabledMark == 1).Select((a, b) => b).FirstAsync();
            if (data == null)
                throw Oops.Oh("根据跳检规则记录未查询到跳检配置，请确认");
            if (status.Equals("OK"))
            {
                recordInfo.QualifiedInspNumber++;
            }
            else
            {
                recordInfo.UnqualifiedInspNumber++;
            }

            // 更新跳检规则记录数据
            var isOk = await _repository.Context.Updateable(recordInfo).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
            if (!isOk)
                throw Oops.Oh(ErrorCode.COM1001);

            // 记录明细
            var exemptionrulerecorddetailEntity = new QmsBusiExemptionrulerecorddetailEntity();
            exemptionrulerecorddetailEntity.ParentId = recordInfo.Id;
            exemptionrulerecorddetailEntity.InspectionlotId = id;
            exemptionrulerecorddetailEntity.Status = status;
            var isOk1 = await _repository.Context.Insertable(exemptionrulerecorddetailEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
            if (isOk1 < 1)
                throw Oops.Oh("插入跳检规则记录明细数据失败");

            // 校验规则
            data = CheckRule(recordInfo, data).Result;
        }
        return true;

    }

    /// <summary>
    /// 校验规则
    /// </summary>
    /// <param name="recordInfo"></param>
    /// <param name="stageInfo"></param>
    /// <returns></returns>
    private async Task<QmsBaseInspectionroleEntity> CheckRule(QmsBusiExemptionrulerecordEntity recordInfo, QmsBaseInspectionroleEntity stageInfo)
    {
        string stage = recordInfo.Stage;
        var currentDate = DateTime.Now;
        // 计算间隔天数
        var d = (int)((currentDate - recordInfo.CreatorTime)?.TotalDays ?? 0);
        // 连续天数是否达成
        bool dayCheckResult = false;
        if (stageInfo.JudeCondition.Equals("=") && d == stageInfo.ContinuityDay)
        {
            dayCheckResult = true;
        }
        else if (stageInfo.JudeCondition.Equals(">") && d > stageInfo.ContinuityDay)
        {
            dayCheckResult = true;
        }
        else if (stageInfo.JudeCondition.Equals("<") && d < stageInfo.ContinuityDay)
        {
            dayCheckResult = true;
        }
        else if (stageInfo.JudeCondition.Equals(">=") && d >= stageInfo.ContinuityDay)
        {
            dayCheckResult = true;
        }
        else if (stageInfo.JudeCondition.Equals("<=") && d <= stageInfo.ContinuityDay)
        {
            dayCheckResult = true;
        }
        // 合格数量是否达成
        bool okQtyCheckResult = false;
        if (stageInfo.InspLot != 0 && recordInfo.QualifiedInspNumber >= stageInfo.InspLot)
        {
            okQtyCheckResult = true;
        }
        // 不合格数量是否达成
        bool ngQtyCheckResult = false;
        if (stageInfo.RejectNun != 0 && recordInfo.UnqualifiedInspNumber >= stageInfo.RejectNun)
        {
            ngQtyCheckResult = true;
        }

        if (stageInfo.KeyWord.Equals("and") && dayCheckResult && okQtyCheckResult)
        {
            stage = stageInfo.OkStageNo;
        }
        else if (stageInfo.KeyWord.Equals("or") && (dayCheckResult || okQtyCheckResult))
        {
            stage = stageInfo.OkStageNo;
        }

        if (ngQtyCheckResult)
        {
            stage = stageInfo.NgStageNo;
        }

        // 已经不是当前阶段了，则查询新阶段的信息
        if (!stage.Equals(recordInfo.Stage))
        {
            // 跳出免检阶段需要推送消息
            if (stageInfo.IsExempt == 1)
            {
                // 跳出免检阶段需要推送消息，待实现
            }

            stageInfo = await _repository.Context.Queryable<QmsBaseInspectionrolemainEntity, QmsBaseInspectionroleEntity>((a, b) => a.Id == b.MainId).Where((a, b) => a.Code == recordInfo.RuleCode && b.Stage == stage && a.DeleteMark == null && a.EnabledMark == 1 && b.DeleteMark == null && b.EnabledMark == 1).Select((a, b) => b).FirstAsync();
            if (stageInfo == null)
                throw Oops.Oh("根据跳检规则记录未查询到跳检配置，请确认");

            QmsBusiExemptionrulerecordEntity _exemptionrulerecordEntity = new QmsBusiExemptionrulerecordEntity();
            _exemptionrulerecordEntity.MatnrCode = recordInfo.MatnrCode;
            _exemptionrulerecordEntity.OrderType = recordInfo.OrderType;
            _exemptionrulerecordEntity.SupplierNo = recordInfo.SupplierNo;
            _exemptionrulerecordEntity.RuleCode = recordInfo.RuleCode;
            _exemptionrulerecordEntity.Stage = stage;
            _exemptionrulerecordEntity.QualifiedInspNumber = 0;
            _exemptionrulerecordEntity.UnqualifiedInspNumber = 0;
            var isOk = await _repository.Context.Insertable(_exemptionrulerecordEntity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
            if (isOk < 1)
                throw Oops.Oh("保存跳检规则记录失败");

            // 跳阶段后返回新阶段记录的id
            recordInfo.Id = _exemptionrulerecordEntity.Id;

            // 进入免检阶段需要推送消息
            if (stageInfo.IsExempt == 1)
            {
                // 进入免检阶段需要推送消息，待实现
            }
        }
        return stageInfo;
    }

    /// <summary>
    /// 提交过账.
    /// </summary>
    /// <param name="data">参数.</param>
    /// <returns></returns>
    [HttpPost("Decision")]
    public async Task SubmitDecision([FromBody] JObject _data)
    {
        var data = JArray.Parse(_data["list"].ToString());
        List<QmsBusiInspectionlotEntity> inspectionlotList = new List<QmsBusiInspectionlotEntity>();
        List<QmsBusiInspectionitemdecisionEntity> inspectionitemdecisionList = new List<QmsBusiInspectionitemdecisionEntity>();
        List<QmsBusiDefecthandleEntity> defecthandleList = new List<QmsBusiDefecthandleEntity>();
        List<QmsBusiDefecthandledetailEntity> defecthandledetailList = new List<QmsBusiDefecthandledetailEntity>();
        foreach (var item in data)
        {
            QmsBusiInspectionlotEntity qmsBusiInspectionlotEntity = new QmsBusiInspectionlotEntity();
            qmsBusiInspectionlotEntity.Id = item["id"].ToString();
            qmsBusiInspectionlotEntity.Code = item["code"].ToString();
            qmsBusiInspectionlotEntity.UdNo = Convert.ToInt32(item["udNo"].ToString() == "" ? "0" : item["udNo"].ToString());
            qmsBusiInspectionlotEntity.Decision = item["decision"].ToString();
            qmsBusiInspectionlotEntity.DecisionName = item["decisionName"].ToString();
            qmsBusiInspectionlotEntity.DecisionDesc = item["decisionDesc"].ToString();
            qmsBusiInspectionlotEntity.DestructivenessQty = Convert.ToInt32(item["destructivenessQty"].ToString() == "" ? "0" : item["destructivenessQty"].ToString());
            qmsBusiInspectionlotEntity.ReceiveQty = Convert.ToInt32(item["receiveQty"].ToString() == "" ? "0" : item["receiveQty"].ToString());
            qmsBusiInspectionlotEntity.Status = 3;
            qmsBusiInspectionlotEntity.JudgeStatus = item["judgeStatus"].ToString();
            inspectionlotList.Add(qmsBusiInspectionlotEntity);
            var inspectionList = JArray.Parse(item["inspection"].ToString());
            foreach (var inspection in inspectionList)
            {
                QmsBusiInspectionitemdecisionEntity qmsBusiInspectionitemdecisionEntity = new QmsBusiInspectionitemdecisionEntity();
                qmsBusiInspectionitemdecisionEntity.Code = qmsBusiInspectionlotEntity.Code;
                qmsBusiInspectionitemdecisionEntity.Inspectionlot = inspection["code"].ToString();
                qmsBusiInspectionitemdecisionEntity.IncomingQty = Convert.ToInt32(inspection["incomingQty"].ToString() == "" ? "0" : inspection["incomingQty"].ToString());

                // 合格并且没有破坏性数量，则接收数量等于来料数量
                if (qmsBusiInspectionlotEntity.JudgeStatus.Equals("OK") && qmsBusiInspectionlotEntity.DestructivenessQty == 0)
                {
                    qmsBusiInspectionitemdecisionEntity.DestructivenessQty = 0;
                    qmsBusiInspectionitemdecisionEntity.ReceiveQty = qmsBusiInspectionitemdecisionEntity.IncomingQty;
                    qmsBusiInspectionitemdecisionEntity.RejectQty = 0;
                }
                else
                {
                    qmsBusiInspectionitemdecisionEntity.DestructivenessQty = Convert.ToInt32(inspection["destructivenessQty"].ToString() == "" ? "0" : inspection["destructivenessQty"].ToString());
                    qmsBusiInspectionitemdecisionEntity.ReceiveQty = Convert.ToInt32(inspection["receiveQty"].ToString() == "" ? "0" : inspection["receiveQty"].ToString());
                    qmsBusiInspectionitemdecisionEntity.RejectQty = Convert.ToInt32(inspection["rejectQty"].ToString() == "" ? "0" : inspection["rejectQty"].ToString());
                }
                qmsBusiInspectionitemdecisionEntity.DecisionDesc = qmsBusiInspectionlotEntity.DecisionDesc;

                qmsBusiInspectionlotEntity.DestructivenessQty += qmsBusiInspectionitemdecisionEntity.DestructivenessQty;
                qmsBusiInspectionlotEntity.ReceiveQty += qmsBusiInspectionitemdecisionEntity.ReceiveQty;

                inspectionitemdecisionList.Add(qmsBusiInspectionitemdecisionEntity);
            }

            // 是否需要创建不合格品处理单
            if (qmsBusiInspectionlotEntity.JudgeStatus.Equals("NG"))
            {
                // 获取处理单号
                string code = await _billRullService.GetBillNumber("DefectHandle");
                // 查询检验项目
                // 类型为定性
                // 状态是NG
                // 参考状态是不为Y的
                var inspectionItemList = await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(x => x.Code == qmsBusiInspectionlotEntity.Code && x.Type == "qualitative" && x.Status == "NG" && x.ReferTo != "Y" && x.DeleteMark == null && x.EnabledMark == 1).OrderBy(x => x.CreatorTime, OrderByType.Asc).ToListAsync();
                foreach (var inspectionItem in inspectionItemList)
                {
                    int defectQty = await _repository.Context.Queryable<QmsBusiInspectionitemdefectEntity>().Where(x => x.InspectionItem == inspectionItem.Id).CountAsync();
                    if (defectQty <= 0) continue;

                    QmsBusiDefecthandledetailEntity defecthandledetailEntity = new QmsBusiDefecthandledetailEntity();
                    defecthandledetailEntity.DefectHandleCode = code;
                    defecthandledetailEntity.InspectionItemId = inspectionItem.Id;
                    defecthandledetailEntity.InnspectionCode = inspectionItem.InnspectionCode;
                    defecthandledetailEntity.InnspectionName = inspectionItem.InnspectionName;
                    defecthandledetailEntity.InnspectionEntry = inspectionItem.InnspectionEntry;
                    defecthandledetailEntity.InnspectionEntryName = inspectionItem.InnspectionEntryName;
                    int SamplingQty = inspectionItem.SamplingQty ?? 0;
                    defecthandledetailEntity.SamplingQty = SamplingQty;
                    decimal defectRate = (defectQty / SamplingQty) * 100;
                    defectRate = decimal.Round(defectRate, 2);
                    defecthandledetailEntity.DefectQty = defectQty;
                    defecthandledetailEntity.DefectRate = defectRate;
                    defecthandledetailList.Add(defecthandledetailEntity);
                }
                // 如果存在缺陷记录，则需要创建不合格品处理单
                if (defecthandledetailList.Count > 0)
                {
                    QmsBusiDefecthandleEntity defecthandleEntity = new QmsBusiDefecthandleEntity();
                    defecthandleEntity.Code = code;
                    defecthandleEntity.Status = 0;
                    defecthandleEntity.InspectionLot = item["code"].ToString();
                    defecthandleEntity.BatchNumber = item["batchNumber"].ToString();
                    defecthandleEntity.MaterialCode = item["materialCode"].ToString();
                    defecthandleEntity.MaterialDes = item["materialDes"].ToString();
                    defecthandleEntity.Supplier = item["supplier"].ToString();
                    defecthandleEntity.SupplierDes = item["supplierDes"].ToString();
                    defecthandleEntity.IncomingQty = Convert.ToInt32(item["incomingQty"].ToString() == "" ? "0" : item["incomingQty"].ToString());
                    defecthandleEntity.Problem = "";
                    defecthandleEntity.Decision = item["decision"].ToString();
                    defecthandleEntity.DecisionName = item["decisionName"].ToString();
                    defecthandleEntity.Remark = "";
                    defecthandleList.Add(defecthandleEntity);
                }

            }

        }
        try
        {
            _db.BeginTran();
            // 保存检验批信息
            var isOk = await _repository.Context.Updateable(inspectionlotList).UpdateColumns(x => new { x.UdNo, x.Decision, x.DecisionName, x.DecisionDesc, x.DestructivenessQty, x.ReceiveQty, x.Status, x.LastModifyUserId, x.LastModifyTime }).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
            if (!isOk)
                throw Oops.Oh(ErrorCode.COM1001);
            // 新增保存检验批项使用决策
            if (inspectionitemdecisionList.Count > 0)
            {
                var isOkI = await _repository.Context.Insertable(inspectionitemdecisionList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
                if (isOkI < 1)
                    throw Oops.Oh(ErrorCode.COM1000);
            }
            // 新增不合格品处理单
            if (defecthandleList.Count > 0)
            {
                var isOkI = await _repository.Context.Insertable(defecthandleList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
                if (isOkI < 1)
                    throw Oops.Oh(ErrorCode.COM1000);
            }
            // 新增不合格品处理单明细
            if (defecthandleList.Count > 0)
            {
                var isOkI = await _repository.Context.Insertable(defecthandledetailList).CallEntityMethod(m => m.Creator()).ExecuteCommandAsync();
                if (isOkI < 1)
                    throw Oops.Oh(ErrorCode.COM1000);
            }

            _db.CommitTran();

        }
        catch (Exception ex)
        {
            _db.RollbackTran();
            throw Oops.Oh("提交过账异常：" + ex.Message);
        }
    }


    #region


    /// <summary>
    /// fastReport
    /// </summary>
    /// <param name="id">主键值. 0 不合格 1合格</param>
    /// <returns></returns>
    [HttpGet("fastreportInspectionlot/{id}")]
    public async Task<dynamic> fastreportInspectionlot(string id)
    {
        FileResult ms = null;
        var result = await _repository.FirstOrDefaultAsync(x => x.Id == id);
        //var ob = result.Adapt<QmsBusiInspectionlotInfoOutput>();

        // fr数据源
        Dictionary<string, List<object>> dicList = new Dictionary<string, List<object>>();

        // 检验批项目表
        var qt = await _repository.Context.Queryable<QmsBusiInspectionitemEntity>().Where(a => result.Code.Contains(a.Code))
            .Where(a => a.ReferTo.Equals("N") && a.EnabledMark == 1 && a.DeleteMark == null)
            .ToListAsync();

        if (qt != null && qt.Count > 0)
        {
            // 获取检查水平字典项
            var iType = await _dictionaryDataService.GetList("InspectionType");

            List<object> qtlist = new List<object>();
            var qtarrId = qt.Select(i => i.Id).ToArray();

            // 检验批项目结果
            var qd = await _repository.Context.Queryable<QmsBusiInspectionitemdataEntity>()
                .Where(a => a.Id == id && a.EnabledMark == 1 && a.DeleteMark == null && qtarrId.Contains(a.InspectionItem)).ToListAsync();
            foreach (var item in qt)
            {
                var iTypeObj = iType
                  .Find(d => d.EnCode.Equals(item.Type));

                qtlist.Add(new
                {
                    SamplingTypeDes = item.SamplingTypeDes,
                    InnspectionEntry = item.InnspectionEntryName,
                    InnspectionMethod = item.InnspectionMethodName,
                    Type = iTypeObj?.FullName,
                    SamplingQty = item.SamplingQty,
                    Status = item.Status,
                    Sum = qd.Where(a => a.InspectionItem == item.Id).Count(),
                });
            }
            dicList.Add("QmsBusiInspectionitemdataEntityRef", qtlist);
        }

        // 报检单表
        var qb = await _repository.Context.Queryable<QmsBusiInspectionEntity>().Where(a => result.Code.Contains(a.Code) && a.EnabledMark == 1 && a.DeleteMark == null).ToListAsync();

        if (qb != null && qb.Count > 0)
        {
            List<object> qblist = new List<object>();
            foreach (var item in qb)
            {
                qblist.Add(new
                {
                    Code = item.Code,
                    OrderNo = item.OrderNo,
                    IncomingQty = item.IncomingQty,
                });
            }
            dicList.Add("QmsBusiInspectionEntityRef", qblist);
        }

        Dictionary<string, string> dic = new Dictionary<string, string>();
        dic.Add("MaterialCode", result.MaterialCode);
        dic.Add("Supplier", result.Supplier);
        dic.Add("EmployeeName", result.EmployeeName);
        dic.Add("StartTime", result.StartTime.ToString());
        dic.Add("EndTime", result.EndTime.ToString());
        dic.Add("IncomingQty", result.IncomingQty.ToString());
        dic.Add("Remark", result.Remark);

        if (result?.UdNo == 1)
        {
            // 输出合格fr
            ms = CreateFR.ExportFastReportPDF(dicList, dic, "Qualified.frx", "", "");
        }
        else
        {
            var qtIdArr = qt.Select(s => s.Id).ToArray();
            // 缺陷记录表
            var qf = await _repository.Context.Queryable<QmsBusiInspectionitemdefectEntity>()
                .Where(a => a.EnabledMark == 1 && a.DeleteMark == null && qtIdArr.Contains(a.InspectionItem)).ToListAsync();

            if (qf != null && qf.Count > 0)
            {
                // 获取检查水平字典项
                var iType = await _dictionaryDataService.GetList("severity");

                List<object> qflist = new List<object>();
                foreach (var item in qf)
                {
                    var iTypeObj = iType.Find(d => d.EnCode.Equals(item.Severity));

                    qflist.Add(new
                    {
                        Number = item.Number,
                        DefectName = item.DefectName,
                        DefectQty = item.DefectQty,
                        Severity = iTypeObj?.FullName,
                    });
                }

                dicList.Add("QmsBusiInspectionitemdefectEntityRef", qflist);
            }

            // 输出不合格fr
            ms = CreateFR.ExportFastReportPDF(dicList, dic, "UnQualified.frx", "", "");
        }
        return ms;
    }

    #endregion

    #region 消息通知
    /// <summary>
    /// 检验批逾期推送消息.
    /// </summary>
    /// <param name="messageId">消息模板id.</param>
    /// <param name="Code">检验批号.</param>
    /// <param name="Overdue">逾期状态.</param>
    /// <param name="userList">发送人.</param>
    /// <returns></returns>
    public async Task SendMessage(string messageId, string Type, string Code, string Overdue, List<string> userList)
    {
        if (messageId.IsNotEmptyOrNull())
        {
            // 通过消息模板id查询消息模板信息
            var msgTemplateEntity = await _messageTemplateService.GetInfo(messageId);
            if (msgTemplateEntity != null)
            {
                var bodyDic = new Dictionary<string, object>();
                GetMsgContent(msgTemplateEntity.TemplateJson.ToObject<List<TemplateJsonItem>>(), msgTemplateEntity, Type, Code, Overdue);
                var typeList = new List<string>();
                //if (msgTemplateEntity.IsStationLetter == 1) // 站内消息
                //{
                //    typeList.Add("1");
                //    var value = new
                //    {
                //        Code = Code
                //    };
                //    userList.ForEach(u => bodyDic.Add(u, value));
                //}
                if (msgTemplateEntity.IsEmail == 1) // 邮件通知
                    typeList.Add("2");

                await _messageTemplateService.SendNodeMessage(typeList, msgTemplateEntity, userList, null, bodyDic);
            }
        }
    }

    /// <summary>
    /// 获取消息模板内容.
    /// </summary>
    /// <param name="templateJsonItems"></param>
    /// <param name="messageTemplateEntity"></param>
    /// <param name="Code"></param>
    /// <param name="Overdue"></param>
    private void GetMsgContent(List<TemplateJsonItem> templateJsonItems, MessageTemplateEntity messageTemplateEntity, string Type, string Code, string Overdue)
    {
        foreach (var item in templateJsonItems)
        {
            var value = string.Empty;
            if (item.field.Equals("F_Code"))
            {
                value = Code;
            }
            else if (item.field.Equals("F_Overdue"))
            {
                value = Overdue;
            }
            else if (item.field.Equals("F_Type"))
            {
                value = Type;
            }
            messageTemplateEntity.Title = messageTemplateEntity.Title.Replace("{" + item.field + "}", value);
            messageTemplateEntity.Content = messageTemplateEntity.Content.Replace("{" + item.field + "}", value);
        }
    }
    #endregion
}